using System;
using System.Collections.Generic;

namespace needle.Services.astra.Collections
{
	/// <summary>
	/// <see cref="IndexBasedList{T}"/> based list.
	/// This list uses one <see cref="List"/> as items store.
	/// </summary>
	/// <typeparam name="T">Item type.</typeparam>
	public class OneTypeIndexBasedList<T> : IndexBasedList<T>
	{
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="list">See <see cref="List"/>. If null, new <see cref="List{T}"/> is used.</param>
		public OneTypeIndexBasedList(IList<T> list)
		{
			if (list == null)
				list = new List<T>();
			_list = list;
			IItemsChangeList<T> itemsChangeList = list as IItemsChangeList<T>;
			if (itemsChangeList != null)
				itemsChangeList.ItemsChange += List_ItemsChange;
		}

		/// <summary>
		/// Internal list as items store.
		/// </summary>
		public IList<T> List
		{
			get { return _list; }
		}

		/// <summary>
		/// See <see cref="IndexBasedList{}.UnitedCount"/>.
		/// </summary>
		/// <value><see cref="List"/>.<see cref="IList{}.Count"/>.</value>
		public override int UnitedCount
		{
			get { return this.List.Count; }
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.IsReadOnly"/>.
		/// </summary>
		/// <value><see cref="List"/>.<see cref="IList{}.IsReadOnly"/>.</value>
		public override bool IsReadOnly
		{
			get { return this.List.IsReadOnly; }
		}

		/// <summary>
		/// See <see cref="IndexBasedList{}.GetItem"/>.
		/// </summary>
		/// <remarks>Uses <see cref="List"/>.</remarks>
		protected override T GetItem(int innerIndex)
		{
			return this.List[innerIndex];
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.SetItem"/>.
		/// </summary>
		/// <remarks>Uses <see cref="List"/>.</remarks>
		protected override void SetItem(int innerIndex, T item)
		{
			this.List[innerIndex] = item;
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.InsertItem"/>.
		/// </summary>
		/// <remarks>Uses <see cref="List"/>.</remarks>
		protected override int InsertItem(int index, T item)
		{
			if (!this.IsUnited)
				index = this.List.Count;
			this.List.Insert(index, item);
			return index;
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.RemoveItem"/>.
		/// </summary>
		/// <remarks>Uses <see cref="List"/>.</remarks>
		protected override void RemoveItem(int innerIndex)
		{
			this.List.RemoveAt(innerIndex);
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.ClearItems"/>.
		/// </summary>
		/// <remarks>Uses <see cref="List"/>.</remarks>
		protected override void ClearItems()
		{
			this.List.Clear();
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.GetUnitedInnerIndex"/>.
		/// </summary>
		/// <remarks>Returns unchanged <paramref name="index"/>.</remarks>
		protected override int GetUnitedInnerIndex(int index)
		{
			return index;
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.GetUnitedIndex"/>.
		/// </summary>
		/// <remarks>Returns unchanged <paramref name="innerIndex"/>.</remarks>
		protected override int GetUnitedIndex(int innerIndex)
		{
			return innerIndex;
		}
		/// <summary>
		/// See <see cref="IndexBasedList{}.GetLastUnitedIndexInSubstore"/>.
		/// </summary>
		protected override int GetLastUnitedIndexInSubstore(T item)
		{
			return this.UnitedCount - 1;
		}

		/// <summary>
		/// Translates <see cref="IItemsChangeList{}.ItemsChange"/> event of <see cref="List"/> if it implements it.
		/// </summary>
		private void List_ItemsChange(object sender, ListItemsChangeEventArgs<T> e)
		{
			TranslateInnerItemsChange(e.Change, e.NewItem, e.OldItem, e.NewIndex, e.OldIndex);
		}

		/// <summary>
		/// See <see cref="List"/>.
		/// </summary>
		private IList<T> _list;
	}
}
